home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / unzip42.zip / ZIPINFO.C < prev    next >
C/C++ Source or Header  |  1992-03-19  |  52KB  |  1,368 lines

  1. /*--------------------------------------------------------------------------
  2.  
  3.   zipinfo.c
  4.  
  5.   This program reads all sorts of totally nifty information, including the
  6.   central directory stuff, from a ZIP archive ("zipfile" for short).  It
  7.   started as just a testbed for fooling with zipfiles, but at this point
  8.   it's actually a moderately useful utility.  It also became the basis
  9.   for the rewrite of unzip (3.16 -> 4.0), using the central directory for
  10.   processing rather than the individual (local) file headers.
  11.  
  12.   For myself, I find it convenient to define an alias "ii" (under Unix and
  13.   VMS) or to rename the executable to "ii.exe" (OS/2 and DOS).  This nicely
  14.   complements my Unix long-listing "ll" alias (ls -lF), since zipinfo's de-
  15.   fault action is to produce a Unix-like listing of the archive's contents.
  16.   "ii zipfile" is easier to type than "zipinfo zipfile"...
  17.  
  18.   Another dandy product from your buddies at Newtware!
  19.  
  20.   --------------------------------------------------------------------------
  21.  
  22.   To compile (partial instructions; some of this stuff doesn't exist yet):
  23.  
  24.      under Unix (cc):  make zipinfo
  25.  
  26.      under MS-DOS (TurboC):  make -fMKZIPINF.DOS   (edit appropriately)
  27.  
  28.      under MS-DOS (MSC):  make MKZIPINF.DOS
  29.        (or use Makefile if you have MSC 6.0:  "nmake zi_dos")
  30.  
  31.      under OS/2 (MSC):  make MKZIPINF.DOS   (edit appropriately)
  32.        (or use Makefile if you have MSC 6.0:  "nmake zi_os2")
  33.  
  34.      under Atari OS:  beats me...
  35.  
  36.      under VMS:  @MAKE_ZIPINFO     (see also VMSNOTES)
  37.                  ZIPINFO == $DISKNAME:[DIRECTORY]ZIPINFO.EXE
  38.  
  39.      under Macintosh OS:  who knows?
  40.  
  41.   --------------------------------------------------------------------------
  42.  
  43.   Version:    unzip42.zip (.tar.Z, etc.) for Unix, VMS, OS/2 and MS-DOS
  44.   Source:     wuarchive.wustl.edu (128.252.135.4) in /mirrors/misc/unix
  45.               wsmr-simtel20.army.mil (192.88.110.20) in pd1:[misc.unix]
  46.   Author:     Greg Roelofs, roelofs@amelia.nas.nasa.gov, 23 August 1990
  47.   Copyright:  none (except that some of the file input/output code comes
  48.               from unzip, which has its own copyrights, sort of...MY stuff
  49.               is in the public domain, however)
  50.  
  51.   --------------------------------------------------------------------------*/
  52.  
  53.  
  54.  
  55.  
  56.  
  57. #define ZIPINFO
  58. #include "unzip.h"
  59.  
  60. #define VERSION  "v0.96k BETA of 20 Mar 92"
  61.  
  62.  
  63.  
  64.  
  65.  
  66. /**********************/
  67. /*  Global Variables  */
  68. /**********************/
  69.  
  70. #ifdef EBCDIC
  71.    int  aflag=1;    /* this is so you can read it on the screen  */
  72. #else               /* (basically, entire program is "unzip -c") */
  73.    int  aflag=0;
  74. #endif
  75. int lflag=2;        /* for "ls -l" type listing */
  76.  
  77.  
  78. byte *inbuf, *inptr;    /* input buffer (any size is legal) and pointer */
  79. int incnt;
  80.  
  81. int zipfd;                      /* zipfile file handle */
  82. char zipfn[FILNAMSIZ];
  83.  
  84. char local_hdr_sig[5] = "\120";    /* remaining signature bytes come later:  */
  85. char central_hdr_sig[5] = "\120";  /*  must initialize at runtime so zipinfo */
  86. char end_central_sig[5] = "\120";  /*  executable won't look like a zipfile  */
  87.  
  88. cdir_file_hdr crec;             /* used in zipinfo.c, misc.c */
  89. local_file_hdr lrec;
  90. ecdir_rec ecrec;
  91. struct stat statbuf;            /* used by main() */
  92.  
  93. int process_all_files;
  94. longint extra_bytes=0;          /* used in zipinfo.c, misc.c */
  95. longint cur_zipfile_bufstart;   /* find_end_central_dir, readbuf */
  96.  
  97. min_info info, *pInfo=(&info);
  98.  
  99. byte *extra_field = NULL;       /* currently used by VMS version only */
  100.  
  101.  
  102. byte *outbuf;                   /* buffer for rle look-back, zipfile comment */
  103. byte *outout;                   /* scratch pad for ASCII-native trans */
  104.  
  105. char filename[FILNAMSIZ];
  106. char sig[5];
  107.  
  108.  
  109. char *fnames[2] = {"*", NULL};    /* default filenames vector */
  110. char **fnv = fnames;
  111.  
  112. static byte *hold;
  113. static longint ziplen;
  114. static UWORD hostnum;
  115. static UWORD methnum;
  116. static UWORD extnum;
  117. /*
  118.     UWORD j, yr, mo, dy, hh, mm, members = 0;
  119.     ULONG tot_csize = 0L, tot_ucsize = 0L;
  120.  */
  121.  
  122.  
  123. char *EndSigMsg = "\nwarning:\
  124.   didn't find end-of-central-dir signature at end of central dir.\n";
  125. char *CentSigMsg =
  126.   "error:  expected central file header signature not found (file #%u).\n";
  127. char *SeekMsg =
  128.   "error:  attempt to seek before beginning of zipfile\n%s";
  129.  
  130. #ifdef VMS
  131. char *ReportMsg = "\
  132.   (please check that you have transferred or created the zipfile in the\n\
  133.   appropriate BINARY mode--this includes ftp, Kermit, AND unzip'd zipfiles)\n";
  134. #else /* !VMS */
  135. char *ReportMsg = "\
  136.   (please check that you have transferred or created the zipfile in the\n\
  137.   appropriate BINARY mode and that you have compiled unzip properly)\n";
  138. #endif /* ?VMS */
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145. /******************/
  146. /*  Main program  */
  147. /******************/
  148.  
  149. main(argc, argv)
  150.     int    argc;
  151.     char   *argv[];
  152. {
  153.     char   *s;
  154.     int    c, error=FALSE;
  155.  
  156.  
  157.  
  158. /*---------------------------------------------------------------------------
  159.     Everybody is now "NOTINT16," but this is a nice little piece of code, so
  160.     just comment it out for future reference. :-)
  161.   ---------------------------------------------------------------------------*/
  162.  
  163. #if 0
  164. # ifndef KNOW_IT_WORKS  /* define this to save space, if things already work */
  165. # ifndef DOS_OS2        /* already works (no RISCy OS/2's yet...) */
  166. # ifndef NOTINT16       /* whole point is to see if this NEEDS defining */
  167.     {
  168.         int error=0;
  169.         long testsig;
  170.         static char *mach_type[3] = {"big-endian", "structure-padding",
  171.                                      "big-endian and structure-padding"};
  172.  
  173.         strcpy((char *)&testsig,"012");
  174.         if (testsig != 0x00323130)
  175.             error = 1;
  176.         if (sizeof(cdir_file_hdr) != CREC_SIZE)
  177.             error += 2;
  178.         if (error--)
  179.             fprintf(stderr, "It appears that your machine is %s.  If errors\n\
  180. occur, please try recompiling with \"NOTINT16\" defined (read the\n\
  181. Makefile, or try \"make zipinfo\").\n\n", mach_type[error]);
  182.     }
  183. # endif /* !NOTINT16 */
  184. # endif /* !DOS_OS2 */
  185. # endif /* !KNOW_IT_WORKS */
  186. #endif /* 0 */
  187.  
  188. /*---------------------------------------------------------------------------
  189.     Rip through any command-line options lurking about...
  190.   ---------------------------------------------------------------------------*/
  191.  
  192.     while (--argc > 0 && (*++argv)[0] == '-') {
  193.         s = argv[0] + 1;
  194.         while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
  195.             switch (c) {
  196.                 case ('1'):    /* minimum listing:  just names */
  197.                     lflag = 0;
  198.                     break;
  199.                 case ('l'):    /* default:  "ls -l" type listing */
  200.                     lflag = 2;
  201.                     break;
  202.                 case ('v'):    /* turbo-verbose listing */
  203.                     lflag = 10;
  204.                     break;
  205.                 default:
  206.                     error = TRUE;
  207.                     break;
  208.             }
  209.         }
  210.     }
  211.     if ((argc-- == 0) || error)
  212.         RETURN(usage(error));
  213.  
  214. /*---------------------------------------------------------------------------
  215.     Now get the zipfile name from the command line and see if it exists as a
  216.     regular (non-directory) file.  If not, append the ".zip" suffix.  We don't
  217.     immediately check to see if this results in a good name, but we will do so
  218.     later.  In the meantime, see if there are any member filespecs on the com-
  219.     mand line, and if so, set the filename pointer to point at them.
  220.   ---------------------------------------------------------------------------*/
  221.  
  222.     strcpy(zipfn, *argv++);
  223.     if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR)
  224.         strcat(zipfn, ZSUFX);
  225. #if defined(UNIX) && !defined(VMS)   /* Unix executables have no extension-- */
  226.     else if (statbuf.st_mode & S_IEXEC)  /* might find zip, not zip.zip; etc */
  227.         fprintf(stderr, "\nnote:  file [ %s ] may be an executable\n\n", zipfn);
  228. #endif /* UNIX && !VMS */
  229.  
  230.     if (stat(zipfn, &statbuf)) {       /* try again */
  231.         fprintf(stderr, "error:  can't find zipfile [ %s ]\n", zipfn);
  232.         RETURN(9);                     /* 9:  file not found */
  233.     } else
  234.         ziplen = statbuf.st_size;
  235.  
  236.     if (argc != 0) {
  237.         fnv = argv;
  238.         process_all_files = FALSE;
  239.     } else
  240.         process_all_files = TRUE;      /* for speed */
  241.  
  242. /*---------------------------------------------------------------------------
  243.     Okey dokey, we have everything we need to get started.  Let's roll.
  244.   ---------------------------------------------------------------------------*/
  245.  
  246.     inbuf = (byte *) (malloc(INBUFSIZ + 4));    /* 4 extra for hold[] (below) */
  247.     outbuf = (byte *) (malloc(OUTBUFSIZ + 1));  /* 1 extra for string termin. */
  248.     if (aflag)                  /* if need an ascebc scratch, */
  249.         outout = (byte *) (malloc(OUTBUFSIZ));
  250.     else                        /*  allocate it... */
  251.         outout = outbuf;        /*  else just point to outbuf */
  252.  
  253.     if ((inbuf == NULL) || (outbuf == NULL) || (outout == NULL)) {
  254.         fprintf(stderr, "error:  can't allocate zipinfo buffers\n");
  255.         RETURN(4);              /* 4-8:  insufficient memory */
  256.     }
  257.     hold = &inbuf[INBUFSIZ];    /* to check for boundary-spanning signatures */
  258.  
  259.     RETURN(process_zipfile());  /* keep passing errors back... */
  260.  
  261. }       /* end main() */
  262.  
  263.  
  264.  
  265.  
  266.  
  267. /**********************/
  268. /*  Function usage()  */
  269. /**********************/
  270.  
  271. int usage(error)
  272.     int error;
  273. {
  274.     FILE *usagefp;
  275.  
  276.  
  277. /*---------------------------------------------------------------------------
  278.     If user requested usage, send it to stdout; else send to stderr.
  279.   ---------------------------------------------------------------------------*/
  280.  
  281.     if (error)
  282.         usagefp = (FILE *) stderr;
  283.     else
  284.         usagefp = (FILE *) stdout;
  285.  
  286.     fprintf(usagefp, "\
  287.    ZipInfo:  Zipfile Information Utility %s\n\
  288.    (brought to you by Newtware, Inc., and the fine folks at Info-ZIP)\n\n\
  289.    Usage:  zipinfo [-1lv] file[.zip] [filespec...]\n", VERSION);
  290.     fprintf(usagefp, "\
  291.      -1  list filenames only, one per line (useful for pipes)\n\
  292.      -l  list files in Unix \"ls -l\" format:  default\n\
  293.      -v  list files in verbose, multi-page format\n");
  294. /*
  295.      -p  disable automatic \"more\" function (for pipes) [not implemented]\n");
  296.  */
  297.  
  298. #ifdef VMS
  299.     fprintf(usagefp, "\nRemember that non-lowercase filespecs must be quoted\
  300.  in VMS (e.g., \"Makefile\").\n");
  301. #endif
  302.  
  303.     if (error)
  304.         return 10;    /* 10:  bad or illegal parameters specified */
  305.     else
  306.         return 0;     /* just wanted usage screen: no error */
  307.  
  308. } /* end function usage() */
  309.  
  310.  
  311.  
  312.  
  313.  
  314. /********************************/
  315. /*  Function process_zipfile()  */
  316. /********************************/
  317.  
  318. int process_zipfile()   /* return PK-type error code */
  319. {
  320.     int error=0, error_in_archive;
  321.     longint real_ecrec_offset, expect_ecrec_offset;
  322.  
  323.  
  324. /*---------------------------------------------------------------------------
  325.     Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
  326.     lation, which would corrupt the bitstreams.
  327.   ---------------------------------------------------------------------------*/
  328.  
  329. #ifdef VMS
  330.     {
  331.         int rtype;
  332.  
  333.         VMSmunch(zipfn, GET_RTYPE, (char *)&rtype);
  334.         if (rtype == FAT$C_VARIABLE) {
  335.             fprintf(stderr,
  336.      "\n     Error:  zipfile is in variable-length record format.  Please\n\
  337.      run \"bilf l %s\" to convert the zipfile to stream-LF\n\
  338.      record format.  (Both bilf.c and make_bilf.com are included\n\
  339.      in the VMS unzip distribution.)\n\n", zipfn);
  340.             return 2;           /* 2:  error in zipfile */
  341.         }
  342.         rtype = FAT$C_STREAMLF; /* Unix I/O loves it */
  343.         VMSmunch(zipfn, CHANGE_RTYPE, (char *)&rtype);
  344.     }
  345. #endif
  346.  
  347.     if (open_input_file())      /* this should never happen, given the */
  348.         return (9);             /*   stat() test in main(), but... */
  349.  
  350. /*---------------------------------------------------------------------------
  351.     Reconstruct the various PK signature strings; find and process the end-
  352.     of-central-directory header and the central directory; and close the
  353.     zipfile.
  354.   ---------------------------------------------------------------------------*/
  355.  
  356.     strcat(local_hdr_sig, LOCAL_HDR_SIG);
  357.     strcat(central_hdr_sig, CENTRAL_HDR_SIG);
  358.     strcat(end_central_sig, END_CENTRAL_SIG);
  359.  
  360.     if (find_end_central_dir()) /* not found; nothing to do */
  361.         return (2);             /* 2:  error in zipfile */
  362.  
  363.     real_ecrec_offset = cur_zipfile_bufstart + (inptr-inbuf);
  364. #ifdef TEST
  365.     printf("\n  found end-of-central-dir signature at offset %ld (%.8lXh)\n",
  366.       real_ecrec_offset, real_ecrec_offset);
  367.     printf("    from beginning of file; offset %d (%.4Xh) within block\n",
  368.       inptr-inbuf, inptr-inbuf);
  369. #endif
  370.  
  371.     if ((error_in_archive = process_end_central_dir()) > 1)
  372.         return (error_in_archive);
  373.  
  374.     if (ecrec.number_this_disk == ecrec.num_disk_with_start_central_dir) {
  375.         expect_ecrec_offset = ecrec.offset_start_central_directory +
  376.                               ecrec.size_central_directory;
  377.         if ((extra_bytes = real_ecrec_offset - expect_ecrec_offset) < 0) {
  378.             fprintf(stderr, "\nerror:  missing %ld bytes in zipfile (\
  379. attempting to process anyway)\n\n", -extra_bytes);
  380.             error_in_archive = 2;       /* 2:  (weak) error in zipfile */
  381.         } else if (extra_bytes > 0) {
  382.             if ((ecrec.offset_start_central_directory == 0) &&
  383.                 (ecrec.size_central_directory != 0))   /* zip 1.5 -go bug */
  384.             {
  385.                 fprintf(stderr, "\nerror:  NULL central directory offset (\
  386. attempting to process anyway)\n\n");
  387.                 error_in_archive = 2;   /* 2:  (weak) error in zipfile */
  388.             } else {
  389.                 fprintf(stderr, "\nwarning:  extra %ld bytes at beginning or\
  390.  within zipfile\n          (attempting to process anyway)\n\n", extra_bytes);
  391.                 error_in_archive = 1;   /* 1:  warning error */
  392.             }
  393.         }
  394.         LSEEK( ecrec.offset_start_central_directory )
  395.         if ((error = process_central_dir()) > error_in_archive)
  396.             error_in_archive = error;    /* don't overwrite stronger error */
  397.         if (lflag > 9)
  398.             printf("\n");
  399.     } else {
  400.         fprintf(stderr, "\n\
  401.      Zipfile is part of a multi-disk archive, and this is not the disk on\
  402.      which the central zipfile directory begins.\n");
  403.         error_in_archive = 11;  /* 11:  no files found */
  404.     }
  405.  
  406.     close(zipfd);
  407. #ifdef VMS
  408.     VMSmunch(zipfn, RESTORE_RTYPE, NULL);
  409. #endif
  410.     return (error_in_archive);
  411.  
  412. }       /* end function process_zipfile() */
  413.  
  414.  
  415.  
  416.  
  417.  
  418. /*************************************/
  419. /*  Function find_end_central_dir()  */
  420. /*************************************/
  421.  
  422. int find_end_central_dir()   /* return 0 if found, 1 otherwise */
  423. {
  424.     int       i, numblks;
  425.     longint   tail_len;
  426.  
  427.  
  428.  
  429. /*---------------------------------------------------------------------------
  430.     Treat case of short zipfile separately.
  431.   ---------------------------------------------------------------------------*/
  432.  
  433.     if (ziplen <= INBUFSIZ) {
  434.         lseek(zipfd, 0L, SEEK_SET);
  435.         if ((incnt = read(zipfd,inbuf,(unsigned int)ziplen)) == ziplen)
  436.  
  437.             /* 'P' must be at least 22 bytes from end of zipfile */
  438.             for ( inptr = inbuf+ziplen-22  ;  inptr >= inbuf  ;  --inptr )
  439.                 if ( (ascii_to_native(*inptr) == 'P')  &&
  440.                       !strncmp(inptr, end_central_sig, 4) ) {
  441.                     incnt -= inptr - inbuf;
  442.                     return(0);  /* found it! */
  443.                 }               /* ...otherwise fall through & fail */
  444.  
  445. /*---------------------------------------------------------------------------
  446.     Zipfile is longer than INBUFSIZ:  may need to loop.  Start with short
  447.     block at end of zipfile (if not TOO short).
  448.   ---------------------------------------------------------------------------*/
  449.  
  450.     } else {
  451.         if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) {
  452.             cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
  453.             if ((incnt = read(zipfd,inbuf,(unsigned int)tail_len)) != tail_len)
  454.                 goto fail;      /* shut up, it's expedient. */
  455.  
  456.             /* 'P' must be at least 22 bytes from end of zipfile */
  457.             for ( inptr = inbuf+tail_len-22  ;  inptr >= inbuf  ;  --inptr )
  458.                 if ( (ascii_to_native(*inptr) == 'P')  &&
  459.                       !strncmp(inptr, end_central_sig, 4) ) {
  460.                     incnt -= inptr - inbuf;
  461.                     return(0);  /* found it! */
  462.                 }               /* ...otherwise search next block */
  463.             strncpy(hold, inbuf, 3);    /* sig may span block boundary */
  464.  
  465.         } else {
  466.             cur_zipfile_bufstart = ziplen - tail_len;
  467.         }
  468.  
  469.         /*
  470.          * Loop through blocks of zipfile data, starting at the end and going
  471.          * toward the beginning.  Need only check last 65557 bytes of zipfile:
  472.          * comment may be up to 65535 bytes long, end-of-central-directory rec-
  473.          * ord is 18 bytes (shouldn't hardcode this number, but what the hell:
  474.          * already did so above (22=18+4)), and sig itself is 4 bytes.
  475.          * 
  476.          * zipinfo:  check the whole file, just in case some transfer protocol
  477.          * has appended a whole bunch of garbage at the end of the archive.
  478.          */
  479.  
  480. #ifndef ZIPINFO
  481.         /*         ==amt to search==   ==done==   ==rounding==    =blksiz= */
  482.         numblks = (min(ziplen,65557) - tail_len + (INBUFSIZ-1)) / INBUFSIZ;
  483. #else
  484.         numblks = (    ziplen        - tail_len + (INBUFSIZ-1)) / INBUFSIZ;
  485. #endif
  486.  
  487.         for ( i = 1  ;  i <= numblks  ;  ++i ) {
  488.             cur_zipfile_bufstart -= INBUFSIZ;
  489.             lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
  490.             if ((incnt = read(zipfd,inbuf,INBUFSIZ)) != INBUFSIZ)
  491.                 break;          /* fall through and fail */
  492.  
  493.             for ( inptr = inbuf+INBUFSIZ-1  ;  inptr >= inbuf  ;  --inptr )
  494.                 if ( (ascii_to_native(*inptr) == 'P')  &&
  495.                       !strncmp(inptr, end_central_sig, 4) ) {
  496.                     incnt -= inptr - inbuf;
  497.                     return(0);  /* found it! */
  498.                 }
  499.             strncpy(hold, inbuf, 3);    /* sig may span block boundary */
  500.         }
  501.  
  502.     } /* end if (ziplen > INBUFSIZ) */
  503.  
  504. /*---------------------------------------------------------------------------
  505.     Searched through whole region where signature should be without finding
  506.     it.  Print informational message and die a horrible death.
  507.   ---------------------------------------------------------------------------*/
  508.  
  509. fail:
  510.  
  511.     fprintf(stderr, "\n\
  512.      End-of-central-directory signature not found.  Either this file is not\n\
  513.      a zipfile, or it constitutes one disk of a multi-part archive.  In the\n\
  514.      latter case the central directory and zipfile comment will be found on\n\
  515.      the last disk(s) of this archive.\n");
  516.     return(1);          /* failed */
  517.  
  518. }       /* end function find_end_central_dir() */
  519.  
  520.  
  521.  
  522.  
  523.  
  524. /****************************************/
  525. /*  Function process_end_central_dir()  */
  526. /****************************************/
  527.  
  528. int process_end_central_dir()   /* return PK-type error code */
  529. {
  530.     ec_byte_rec   byterec;
  531.     int           error=0;
  532.  
  533.  
  534. /*--------------------------------------------------------------------------
  535.     Read the end-of-central-directory record and do any necessary machine-
  536.     type conversions (byte ordering, structure padding compensation) by
  537.     copying character array to struct.
  538.   ---------------------------------------------------------------------------*/
  539.  
  540.     if (readbuf((char *) byterec, ECREC_SIZE+4) <= 0)
  541.         return (51);
  542.  
  543.     ecrec.number_this_disk =
  544.         makeword(&byterec[NUMBER_THIS_DISK]);
  545.     ecrec.num_disk_with_start_central_dir =
  546.         makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
  547.     ecrec.num_entries_centrl_dir_ths_disk =
  548.         makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
  549.     ecrec.total_entries_central_dir =
  550.         makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
  551.     ecrec.size_central_directory =
  552.         makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
  553.     ecrec.offset_start_central_directory =
  554.         makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
  555.     ecrec.zipfile_comment_length =
  556.         makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
  557.  
  558. /*---------------------------------------------------------------------------
  559.     Print out various interesting things about the zipfile.
  560.   ---------------------------------------------------------------------------*/
  561.  
  562.     if (lflag == 2) {
  563.         if (process_all_files)
  564.            /* fits on one line, for anything up to 10GB and 10000 files */
  565.            printf((strlen(zipfn)<39)? "Archive:  %s   %ld bytes   %d file%s\n"
  566.              : "Archive:  %s   %ld   %d\n", zipfn, ziplen,
  567.              ecrec.total_entries_central_dir,
  568.              (ecrec.total_entries_central_dir==1)? "":"s");
  569.     } else if (lflag > 9) {   /* verbose format */
  570.         printf("\nEnd-of-central-directory record:\n");
  571.         printf("-------------------------------\n\n");
  572.  
  573.         if (ecrec.number_this_disk == 0) {
  574.             printf("\
  575.   This zipfile constitutes the sole disk of a single-part archive; its\n\
  576.   central directory contains %u %s.  The central directory is %lu\n\
  577.   (%.8lXh) bytes long, and its offset in bytes from the beginning of\n\
  578.   the zipfile is %lu (%.8lXh).\n\n",
  579.               ecrec.total_entries_central_dir,
  580.               (ecrec.total_entries_central_dir == 1)? "entry" : "entries",
  581.               ecrec.size_central_directory, ecrec.size_central_directory,
  582.               ecrec.offset_start_central_directory,
  583.               ecrec.offset_start_central_directory);
  584.         } else {
  585.             printf("\
  586.   This zipfile constitutes disk %u of a multi-part archive.  The central\n\
  587.   directory starts on disk %u; %u of its entries %s contained within\n\
  588.   this zipfile, out of a total of %u %s.  The entire central\n\
  589.   directory is %lu (%.8lXh) bytes long, and its offset in bytes from\n\
  590.   the beginning of the zipfile in which it begins is %lu (%.8lXh).\n\n",
  591.               ecrec.number_this_disk,
  592.               ecrec.num_disk_with_start_central_dir,
  593.               ecrec.num_entries_centrl_dir_ths_disk,
  594.               (ecrec.num_entries_centrl_dir_ths_disk == 1)? "is" : "are",
  595.               ecrec.total_entries_central_dir,
  596.               (ecrec.total_entries_central_dir == 1) ? "entry" : "entries",
  597.               ecrec.size_central_directory, ecrec.size_central_directory,
  598.               ecrec.offset_start_central_directory,
  599.               ecrec.offset_start_central_directory);
  600.         }
  601.  
  602.     /*-----------------------------------------------------------------------
  603.         Get the zipfile comment, if any, and print it out.  (Comment may be
  604.         up to 64KB long.  May the fleas of a thousand camels infest the arm-
  605.         pits of anyone who actually takes advantage of this fact.)
  606.       -----------------------------------------------------------------------*/
  607.  
  608.         if (!ecrec.zipfile_comment_length)
  609.             printf("  There is no zipfile comment.\n");
  610.         else {
  611.             printf("  The zipfile comment is %u bytes long and contains the following text:\n\n",
  612.               ecrec.zipfile_comment_length );
  613.             printf("======================== zipfile comment begins ==========================\n");
  614.             if (do_string(ecrec.zipfile_comment_length, DISPLAY))
  615.                 error = 1;          /* 1:  warning error */
  616.             printf("\n========================= zipfile comment ends ===========================\n");
  617.             if (error)
  618.                 printf("\n  The zipfile comment is truncated.\n");
  619.         } /* endif (comment exists) */
  620.  
  621.     } /* endif (verbose) */
  622.  
  623.     return error;
  624.  
  625. }       /* end function process_end_central_dir() */
  626.  
  627.  
  628.  
  629.  
  630.  
  631. /******************************************/
  632. /*  Function process_central_directory()  */
  633. /******************************************/
  634.  
  635. int process_central_dir()   /* return PK-type error code */
  636. {
  637.     char    **fnamev;
  638.     int     do_this_file=FALSE, none_found=TRUE, error, error_in_archive=0;
  639.     UWORD   j, members=0;
  640.     ULONG   tot_csize=0L, tot_ucsize=0L;
  641.  
  642.  
  643. /*---------------------------------------------------------------------------
  644.     Set file pointer to start of central directory, then loop through cen-
  645.     tral directory entries.  Check that directory-entry signature bytes are
  646.     actually there (just a precaution), then process the entry.  We know
  647.     the entire central directory is on this disk:  we wouldn't have any of
  648.     this information unless the end-of-central-directory record was on this
  649.     disk, and we wouldn't have gotten to this routine unless this is also
  650.     the disk on which the central directory starts.  In practice, this had
  651.     better be the *only* disk in the archive, but maybe someday we'll add
  652.     multi-disk support.
  653.   ---------------------------------------------------------------------------*/
  654.  
  655.     pInfo->lcflag = 0;   /* match(), do_string():  never TRUE in zipinfo */
  656.  
  657.     for (j = 0;  j < ecrec.total_entries_central_dir;  ++j) {
  658.         if (readbuf(sig, 4) <= 0)
  659.             return (51);        /* 51:  unexpected EOF */
  660.         if (strncmp(sig, central_hdr_sig, 4)) {  /* just to make sure */
  661.             fprintf(stderr, CentSigMsg, j);  /* sig not found */
  662.             return (3);         /* 3:  error in zipfile */
  663.         }
  664.         if ((error = process_cdir_file_hdr()) != 0)
  665.             return (error);     /* only 51 (EOF) defined */
  666.         if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
  667.           error_in_archive = error;   /* might be warning */
  668.           if (error > 1)        /* fatal */
  669.               return (error);
  670.         }
  671.  
  672.         if (!process_all_files) {   /* check if specified on command line */
  673.             do_this_file = FALSE;
  674.             fnamev = fnv;       /* don't destroy permanent filename ptr */
  675.             for (--fnamev;  *++fnamev; )
  676.                 if (match(filename, *fnamev)) {
  677.                     do_this_file = TRUE;
  678.                     none_found = FALSE;
  679.                     break;      /* found match, so stop looping */
  680.                 }
  681.         }
  682.  
  683.     /*-----------------------------------------------------------------------
  684.         If current file was specified on command line, or if no names were
  685.         specified, do the listing for this file.  Otherwise, get rid of the
  686.         file comment and go back for the next file.
  687.       -----------------------------------------------------------------------*/
  688.  
  689.         if (process_all_files || do_this_file) {
  690.             switch (lflag) {
  691.                 case 0:
  692.                     printf("%s\n", filename);
  693.                     SKIP_(crec.extra_field_length)
  694.                     SKIP_(crec.file_comment_length)
  695.                     break;
  696.  
  697.                 case 2:
  698.                     if ((error = short_info()) != 0) {
  699.                         error_in_archive = error;   /* might be warning */
  700.                         if (error > 1)              /* fatal */
  701.                             return (error);
  702.                     }
  703.                     break;
  704.  
  705.                 case 10:
  706. #ifdef VMS   /* GRR: FIX THIS (no pipes:  add cbreak-style "more" function) */
  707.                     printf("\nCentral directory entry #%d:\n", j);
  708. #else /* !VMS */
  709.                     /* formfeed/CR for piping to "more": */
  710.                     printf("%s\nCentral directory entry #%d:\n", "\014", j);
  711. #endif /* ?VMS */
  712.                     printf("---------------------------\n\n");
  713.  
  714.                     if ((error = long_info()) != 0) {
  715.                       error_in_archive = error;   /* might be warning */
  716.                       if (error > 1)              /* fatal */
  717.                           return (error);
  718.                     }
  719.                     break;
  720.  
  721.                 default:
  722.                     SKIP_(crec.extra_field_length)
  723.                     SKIP_(crec.file_comment_length)
  724.                     break;
  725.  
  726.             } /* end switch (lflag) */
  727.  
  728.             tot_ucsize += crec.uncompressed_size;
  729.             tot_csize += crec.compressed_size;
  730.             ++members;
  731.  
  732.         } else {   /* not listing */
  733.             SKIP_(crec.extra_field_length)
  734.             SKIP_(crec.file_comment_length)
  735.  
  736.         } /* end if (list member?) */
  737.  
  738.     } /* end for-loop (j: member files) */
  739.  
  740. /*---------------------------------------------------------------------------
  741.     Double check that we're back at the end-of-central-directory record.
  742.   ---------------------------------------------------------------------------*/
  743.  
  744.     readbuf(sig, 4);
  745.     if (strncmp(sig, end_central_sig, 4)) {     /* just to make sure again */
  746.         fprintf(stderr, EndSigMsg);  /* didn't find end-of-central-dir sig */
  747.         error_in_archive = 1;        /* 1:  warning error */
  748.     }
  749.  
  750. /*---------------------------------------------------------------------------
  751.     Check that we actually found requested files.
  752.   ---------------------------------------------------------------------------*/
  753.  
  754.     if (none_found && !process_all_files) {
  755.         fnamev = fnv;       /* don't destroy permanent filename ptr */
  756.         for (--fnamev;  *++fnamev; )
  757.             printf("zipinfo:  %s not found in %s\n", *fnamev, zipfn);
  758.     }
  759.  
  760.     return (error_in_archive);
  761. }
  762.  
  763.  
  764.  
  765.  
  766.  
  767. /**************************************/
  768. /*  Function process_cdir_file_hdr()  */
  769. /**************************************/
  770.  
  771. int process_cdir_file_hdr()   /* return PK-type error code */
  772. {
  773.     cdir_byte_hdr   byterec;
  774.  
  775.  
  776. /*---------------------------------------------------------------------------
  777.     Read the next central directory entry and do any necessary machine-type
  778.     conversions (byte ordering, structure padding compensation--do so by
  779.     copying the data from the array into which it was read (byterec) to the
  780.     usable struct (crec)).
  781.   ---------------------------------------------------------------------------*/
  782.  
  783.     if (readbuf((char *) byterec, CREC_SIZE) <= 0)
  784.         return (51);            /* 51:  unexpected EOF */
  785.  
  786.     crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
  787.     crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
  788.     crec.version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
  789.     crec.version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
  790.  
  791.     crec.general_purpose_bit_flag =
  792.         makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
  793.     crec.compression_method =
  794.         makeword(&byterec[C_COMPRESSION_METHOD]);
  795.     crec.last_mod_file_time =
  796.         makeword(&byterec[C_LAST_MOD_FILE_TIME]);
  797.     crec.last_mod_file_date =
  798.         makeword(&byterec[C_LAST_MOD_FILE_DATE]);
  799.     crec.crc32 =
  800.         makelong(&byterec[C_CRC32]);
  801.     crec.compressed_size =
  802.         makelong(&byterec[C_COMPRESSED_SIZE]);
  803.     crec.uncompressed_size =
  804.         makelong(&byterec[C_UNCOMPRESSED_SIZE]);
  805.     crec.filename_length =
  806.         makeword(&byterec[C_FILENAME_LENGTH]);
  807.     crec.extra_field_length =
  808.         makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
  809.     crec.file_comment_length =
  810.         makeword(&byterec[C_FILE_COMMENT_LENGTH]);
  811.     crec.disk_number_start =
  812.         makeword(&byterec[C_DISK_NUMBER_START]);
  813.     crec.internal_file_attributes =
  814.         makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
  815.     crec.external_file_attributes =
  816.         makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */
  817.     crec.relative_offset_local_header =
  818.         makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
  819.  
  820.     return (0);
  821.  
  822. } /* end function process_cdir_file_hdr() */
  823.  
  824.  
  825.  
  826.  
  827. /**************************/
  828. /*  Function long_info()  */
  829. /**************************/
  830.  
  831. int long_info()   /* return PK-type error code */
  832. {
  833.     int           error, error_in_archive=0;
  834.     UWORD         hostver, extver, xattr;
  835.     char          workspace[12], attribs[22];
  836.     static char   unkn[16];
  837.     static char   *os[NUM_HOSTS+1] = {"MS-DOS or OS/2 FAT", "Amiga", "VAX VMS",
  838.                       "Unix", "VM/CMS", "Atari ST", "OS/2 HPFS", "Macintosh",
  839.                       "Z-System", "CP/M", "unknown" };
  840.     static char   *method[NUM_METHODS+1] = {"none (stored)", "shrunk",
  841.                       "reduced (factor 1)", "reduced (factor 2)",
  842.                       "reduced (factor 3)", "reduced (factor 4)",
  843.                       "imploded", "tokenized", "deflated", unkn};
  844.     static char   *dtype[4] = {"normal", "maximum", "fastest", "undefined"};
  845.  
  846.  
  847. /*---------------------------------------------------------------------------
  848.     Print out various interesting things about the compressed file.
  849.   ---------------------------------------------------------------------------*/
  850.  
  851.     hostnum = min(crec.version_made_by[1], NUM_HOSTS);
  852.     hostver = crec.version_made_by[0];
  853.     extnum = min(crec.version_needed_to_extract[1], NUM_HOSTS);
  854.     extver = crec.version_needed_to_extract[0];
  855.     methnum = min(crec.compression_method, NUM_METHODS);
  856.     if (methnum == NUM_METHODS)
  857.         sprintf(unkn, "unknown (%d)", crec.compression_method);
  858.  
  859.     printf("  %s\n", filename);
  860.  
  861.     printf("\n  host operating system (created on):               %s\n",
  862.       os[hostnum]);
  863.     printf("  version of encoding software:                     %d.%d\n",
  864.       hostver/10, hostver%10);
  865.     printf("  minimum operating system compatibility required:  %s\n",
  866.       os[extnum]);
  867.     printf("  minimum software version required to extract:     %d.%d\n",
  868.       extver/10, extver%10);
  869.     printf("  compression method:                               %s\n",
  870.       method[methnum]);
  871.     if (methnum == IMPLODED) {
  872.         printf("  size of sliding dictionary (implosion):           %cK\n",
  873.           (crec.general_purpose_bit_flag & 2)? '8' : '4');
  874.         printf("  number of Shannon-Fano trees (implosion):         %c\n",
  875.           (crec.general_purpose_bit_flag & 4)? '3' : '2');
  876.     } else if (methnum == DEFLATED) {
  877.         UWORD  dnum=(crec.general_purpose_bit_flag>>1) & 3;
  878.         printf("  compression sub-type (deflation):                 %s\n",
  879.           dtype[dnum]);
  880.     }
  881.     printf("  file security status:                             %sencrypted\n",
  882.       (crec.general_purpose_bit_flag & 1)? "" : "not ");
  883.     printf("  extended local header:                            %s\n",
  884.       (crec.general_purpose_bit_flag & 8)? "yes" : "no");
  885.     /* print upper 3 bits for amusement? */
  886.     printf("  file last modified on:                            %s\n",
  887.       zipinfo_time(&crec.last_mod_file_date, &crec.last_mod_file_time));
  888.     printf("  32-bit CRC value (hex):                           %.8lx\n",
  889.       crec.crc32);
  890.     printf("  compressed size:                                  %lu bytes\n",
  891.       crec.compressed_size);
  892.     printf("  uncompressed size:                                %lu bytes\n",
  893.       crec.uncompressed_size);
  894.     printf("  length of filename:                               %u characters\n",
  895.       crec.filename_length);
  896.     printf("  length of extra field:                            %u bytes\n",
  897.       crec.extra_field_length);
  898.     printf("  length of file comment:                           %u characters\n",
  899.       crec.file_comment_length);
  900.     printf("  disk number on which file begins:                 disk %u\n",
  901.       crec.disk_number_start);
  902.     printf("  apparent file type:                               %s\n",
  903.       (crec.internal_file_attributes & 1)? "text" : "binary");
  904. /*
  905.     printf("  external file attributes (hex):                   %.8lx\n",
  906.       crec.external_file_attributes);
  907.  */
  908.     xattr = (crec.external_file_attributes >> 16) & 0xFFFF;
  909.     if (hostnum == VMS_) {
  910.         char   *p=attribs, *q=attribs+1;
  911.         int    i, j, k;
  912.  
  913.         for (k = 0;  k < 12;  ++k)
  914.             workspace[k] = 0;
  915.         if (xattr & S_IRUSR)
  916.             workspace[0] = 'R';
  917.         if (xattr & S_IWUSR) {
  918.             workspace[1] = 'W';
  919.             workspace[3] = 'D';
  920.         }
  921.         if (xattr & S_IXUSR)
  922.             workspace[2] = 'E';
  923.         if (xattr & S_IRGRP)
  924.             workspace[4] = 'R';
  925.         if (xattr & S_IWGRP) {
  926.             workspace[5] = 'W';
  927.             workspace[7] = 'D';
  928.         }
  929.         if (xattr & S_IXGRP)
  930.             workspace[6] = 'E';
  931.         if (xattr & S_IROTH)
  932.             workspace[8] = 'R';
  933.         if (xattr & S_IWOTH) {
  934.             workspace[9] = 'W';
  935.             workspace[11] = 'D';
  936.         }
  937.         if (xattr & S_IXOTH)
  938.             workspace[10] = 'E';
  939.  
  940.         *p++ = '(';
  941.         for (k = j = 0;  j < 3;  ++j) {    /* loop over groups of permissions */
  942.             for (i = 0;  i < 4;  ++i, ++k)  /* loop over perms within a group */
  943.                 if (workspace[k])
  944.                     *p++ = workspace[k];
  945.             *p++ = ',';                      /* group separator */
  946.             if (j == 0)
  947.                 while ((*p++ = *q++) != ','); /* system, owner perms are same */
  948.         }
  949.         *p-- = 0;
  950.         *p = ')';   /* overwrite last comma */
  951.         printf("  VMS file attributes (%06o octal):               %s\n",
  952.           xattr, attribs);
  953.  
  954.     } else if ((hostnum != DOS_OS2_FAT_) && (hostnum != OS2_HPFS_)) {
  955.         /* assume Unix-like */
  956.         switch (xattr & S_IFMT) {
  957.             case S_IFREG:   attribs[0] = '-';  break;
  958.             case S_IFLNK:   attribs[0] = 'l';  break;
  959.             case S_IFBLK:   attribs[0] = 'b';  break;
  960.             case S_IFCHR:   attribs[0] = 'c';  break;
  961.             case S_IFIFO:   attribs[0] = 'p';  break;
  962.             case S_IFSOCK:  attribs[0] = 's';  break;
  963.             case S_IFDIR:   attribs[0] = 'd';  break;
  964.             default:        attribs[0] = '?';  break;
  965.         }
  966.         if (xattr & S_IRUSR)        /* no read-permission: user */
  967.             attribs[1] = 'r';
  968.         else
  969.             attribs[1] = '-';
  970.         if (xattr & S_IWUSR)        /* no write-permission: user */
  971.             attribs[2] = 'w';
  972.         else
  973.             attribs[2] = '-';
  974.         if (xattr & S_IXUSR)        /* no execute-permission: user */
  975.             if (xattr & S_ISUID)
  976.                 attribs[3] = 's';
  977.             else
  978.                 attribs[3] = 'x';
  979.         else
  980.             if (xattr & S_ISUID)
  981.                 attribs[3] = 'S';   /* undefined state */
  982.             else
  983.                 attribs[3] = '-';
  984.         if (xattr & S_IRGRP)        /* no read-permission: group */
  985.             attribs[4] = 'r';
  986.         else
  987.             attribs[4] = '-';
  988.         if (xattr & S_IWGRP)        /* no write-permission: group */
  989.             attribs[5] = 'w';
  990.         else
  991.             attribs[5] = '-';
  992.         if (xattr & S_IXGRP)        /* no execute-permission: group */
  993.             if (xattr & S_ISGID)
  994.                 attribs[6] = 's';
  995.             else
  996.                 attribs[6] = 'x';
  997.         else
  998.             if (xattr & S_ISGID)    /* or could use S_ENFMT (same) */
  999.                 attribs[6] = 'l';
  1000.             else
  1001.                 attribs[6] = '-';
  1002.         if (xattr & S_IROTH)        /* no read-permission: other */
  1003.             attribs[7] = 'r';
  1004.         else
  1005.             attribs[7] = '-';
  1006.         if (xattr & S_IWOTH)        /* no write-permission: other */
  1007.             attribs[8] = 'w';
  1008.         else
  1009.             attribs[8] = '-';
  1010.         if (xattr & S_IXOTH)        /* no execute-permission: other */
  1011.             if (xattr & S_ISVTX)    /* "sticky bit" */
  1012.                 attribs[9] = 't';
  1013.             else
  1014.                 attribs[9] = 'x';
  1015.         else
  1016.             if (xattr & S_ISVTX)
  1017.                 attribs[9] = 'T';   /* undefined state */
  1018.             else
  1019.                 attribs[9] = '-';
  1020.         attribs[10] = 0;
  1021.         printf("  Unix file attributes (%06o octal):              %s\n",
  1022.           xattr, attribs);
  1023.  
  1024.     } /* endif (hostnum: external attributes format) */
  1025.  
  1026.     if ((xattr=crec.external_file_attributes & 0xFF) == 0)
  1027.         printf("  MS-DOS file attributes (%02X hex):                  none\n",
  1028.           xattr);
  1029.     else if (xattr == 1)
  1030.         printf(
  1031.           "  MS-DOS file attributes (%02X hex):                  read-only\n",
  1032.           xattr);
  1033.     else
  1034.         printf(
  1035.          "  MS-DOS file attributes (%02X hex):                  %s%s%s%s%s%s\n",
  1036.           xattr, (xattr&1)?"rdo ":"", (xattr&2)?"hid ":"", (xattr&4)?"sys ":"",
  1037.           (xattr&8)?"lab ":"", (xattr&16)?"dir ":"", (xattr&32)?"arc":"");
  1038.     printf(
  1039.      "  offset of local header from start of archive:     %lu (%.8lXh) bytes\n",
  1040.       crec.relative_offset_local_header, crec.relative_offset_local_header);
  1041.  
  1042. /*---------------------------------------------------------------------------
  1043.     Skip the extra field, if any, and print the file comment, if any (the
  1044.     filename has already been printed, above).  That finishes up this file
  1045.     entry...
  1046.   ---------------------------------------------------------------------------*/
  1047.  
  1048.     if (crec.extra_field_length > 0) {
  1049.         printf("\n  There is an extra field (skipping).\n");
  1050.         SKIP_(crec.extra_field_length)
  1051.     } else
  1052.         printf("\n");
  1053.  
  1054.     if (!crec.file_comment_length)
  1055.         printf("  There is no file comment.\n");
  1056.     else {
  1057.         printf("\
  1058. ------------------------- file comment begins ----------------------------\n");
  1059.         if ((error = do_string(crec.file_comment_length, DISPLAY)) != 0) {
  1060.           error_in_archive = error;   /* might be warning */
  1061.           if (error > 1)      /* fatal */
  1062.               return (error);
  1063.         }
  1064.         printf("\n\
  1065. -------------------------- file comment ends -----------------------------\n");
  1066.     }
  1067.  
  1068.     return (error_in_archive);
  1069.  
  1070. } /* end function long_info() */
  1071.  
  1072.  
  1073.  
  1074.  
  1075.  
  1076. /***************************/
  1077. /*  Function short_info()  */
  1078. /***************************/
  1079.  
  1080. int short_info()   /* return PK-type error code */
  1081. {
  1082.     int           k, error, error_in_archive=0;
  1083.     UWORD         hostver, xattr;
  1084.     char          workspace[12], attribs[16];
  1085.     static char   impl[5]="i#:#", defl[5]="def#", unkn[8];
  1086.     static char   dtype[5]="NXF?";  /* normal, maximum, fastest, undefined */
  1087.     static char   *os[NUM_HOSTS+1] = {"dos", "ami", "vms", "unx", "cms",
  1088.                       "atr", "os2", "mac", "zzz", "cpm", "???" };
  1089.     static char   *method[NUM_METHODS+1] = {"stor", "shrk", "re:1", "re:2",
  1090.                       "re:3", "re:4", impl, "tokn", defl, unkn};
  1091.  
  1092.  
  1093. /*---------------------------------------------------------------------------
  1094.     Print out various interesting things about the compressed file.
  1095.   ---------------------------------------------------------------------------*/
  1096.  
  1097.     methnum = min(crec.compression_method, NUM_METHODS);
  1098.     hostnum = min(crec.version_made_by[1], NUM_HOSTS);
  1099.     hostver = crec.version_made_by[0];
  1100. /*
  1101.     extnum = min(crec.version_needed_to_extract[1], NUM_HOSTS);
  1102.     extver = crec.version_needed_to_extract[0];
  1103.  */
  1104.  
  1105.     if (methnum == IMPLODED) {
  1106.         impl[1] = (crec.general_purpose_bit_flag & 2)? '8' : '4';
  1107.         impl[3] = (crec.general_purpose_bit_flag & 4)? '3' : '2';
  1108.     } else if (methnum == DEFLATED) {
  1109.         UWORD  dnum=(crec.general_purpose_bit_flag>>1) & 3;
  1110.         defl[3] = dtype[dnum];
  1111.     } else if (methnum == NUM_METHODS) {   /* unknown */
  1112.         sprintf(unkn, "u%03d", crec.compression_method);
  1113.     }
  1114.  
  1115.     for (k = 0;  k < 15;  ++k)
  1116.         attribs[k] = ' ';
  1117.     attribs[15] = 0;
  1118.  
  1119.     xattr = (crec.external_file_attributes >> 16) & 0xFFFF;
  1120.     switch (hostnum) {
  1121.       case VMS_:
  1122.           {   char   *p=attribs;
  1123.               int    i, j;
  1124.  
  1125.               for (k = 0;  k < 12;  ++k)
  1126.                   workspace[k] = 0;
  1127.               if (xattr & S_IRUSR)
  1128.                   workspace[0] = 'R';
  1129.               if (xattr & S_IWUSR) {
  1130.                   workspace[1] = 'W';
  1131.                   workspace[3] = 'D';
  1132.               }
  1133.               if (xattr & S_IXUSR)
  1134.                   workspace[2] = 'E';
  1135.               if (xattr & S_IRGRP)
  1136.                   workspace[4] = 'R';
  1137.               if (xattr & S_IWGRP) {
  1138.                   workspace[5] = 'W';
  1139.                   workspace[7] = 'D';
  1140.               }
  1141.               if (xattr & S_IXGRP)
  1142.                 workspace[6] = 'E';
  1143.               if (xattr & S_IROTH)
  1144.                   workspace[8] = 'R';
  1145.               if (xattr & S_IWOTH) {
  1146.                   workspace[9] = 'W';
  1147.                   workspace[11] = 'D';
  1148.               }
  1149.               if (xattr & S_IXOTH)
  1150.                   workspace[10] = 'E';
  1151.  
  1152.               for (k = j = 0;  j < 3;  ++j) {     /* groups of permissions */
  1153.                   for (i = 0;  i < 4;  ++i, ++k)  /* perms within a group */
  1154.                       if (workspace[k])
  1155.                           *p++ = workspace[k];
  1156.                   *p++ = ',';                     /* group separator */
  1157.               }
  1158.               *--p = ' ';   /* overwrite last comma */
  1159.               if ((p - attribs) < 12)
  1160.                   sprintf(&attribs[12], "%d.%d", hostver/10, hostver%10);
  1161.           }
  1162.           break;
  1163.  
  1164.       case DOS_OS2_FAT_:
  1165.       case OS2_HPFS_:
  1166.           xattr = crec.external_file_attributes & 0xFF;
  1167.           sprintf(attribs, "%s,%s,%s,%s", (xattr&32)?"arc":"",
  1168.             (xattr&2)?"hid":"", (xattr&1)?"rdo":"rw", (xattr&4)?"sys":"");
  1169.           if ((k = strlen(attribs)) < 15)
  1170.               attribs[k] = ' ';   /* overwrite '\0' */
  1171.           if (k < 12)
  1172.               sprintf(&attribs[12], "%d.%d", hostver/10, hostver%10);
  1173.           break;
  1174.  
  1175.       default:   /* assume Unix-like */
  1176.           switch (xattr & S_IFMT) {
  1177.               case S_IFREG:   attribs[0] = '-';  break;
  1178.               case S_IFLNK:   attribs[0] = 'l';  break;
  1179.               case S_IFBLK:   attribs[0] = 'b';  break;
  1180.               case S_IFCHR:   attribs[0] = 'c';  break;
  1181.               case S_IFIFO:   attribs[0] = 'p';  break;
  1182.               case S_IFSOCK:  attribs[0] = 's';  break;
  1183.               case S_IFDIR:   attribs[0] = 'd';  break;
  1184.               default:        attribs[0] = '?';  break;
  1185.           }
  1186.           if (xattr & S_IRUSR)        /* no read-permission: user */
  1187.               attribs[1] = 'r';
  1188.           else
  1189.               attribs[1] = '-';
  1190.           if (xattr & S_IWUSR)        /* no write-permission: user */
  1191.               attribs[2] = 'w';
  1192.           else
  1193.               attribs[2] = '-';
  1194.           if (xattr & S_IXUSR)        /* no execute-permission: user */
  1195.               if (xattr & S_ISUID)
  1196.                   attribs[3] = 's';
  1197.               else
  1198.                   attribs[3] = 'x';
  1199.           else
  1200.               if (xattr & S_ISUID)
  1201.                   attribs[3] = 'S';   /* undefined state */
  1202.               else
  1203.                   attribs[3] = '-';
  1204.           if (xattr & S_IRGRP)        /* no read-permission: group */
  1205.               attribs[4] = 'r';
  1206.           else
  1207.               attribs[4] = '-';
  1208.           if (xattr & S_IWGRP)        /* no write-permission: group */
  1209.               attribs[5] = 'w';
  1210.           else
  1211.               attribs[5] = '-';
  1212.           if (xattr & S_IXGRP)        /* no execute-permission: group */
  1213.               if (xattr & S_ISGID)
  1214.                   attribs[6] = 's';
  1215.               else
  1216.                   attribs[6] = 'x';
  1217.           else
  1218.               if (xattr & S_ISGID)    /* or could use S_ENFMT (same) */
  1219.                   attribs[6] = 'l';
  1220.               else
  1221.                   attribs[6] = '-';
  1222.           if (xattr & S_IROTH)        /* no read-permission: other */
  1223.               attribs[7] = 'r';
  1224.           else
  1225.               attribs[7] = '-';
  1226.           if (xattr & S_IWOTH)        /* no write-permission: other */
  1227.               attribs[8] = 'w';
  1228.           else
  1229.               attribs[8] = '-';
  1230.           if (xattr & S_IXOTH)        /* no execute-permission: other */
  1231.               if (xattr & S_ISVTX)    /* "sticky bit" */
  1232.                   attribs[9] = 't';
  1233.               else
  1234.                   attribs[9] = 'x';
  1235.           else
  1236.               if (xattr & S_ISVTX)
  1237.                   attribs[9] = 'T';   /* undefined state */
  1238.               else
  1239.                   attribs[9] = '-';
  1240.           sprintf(&attribs[12], "%d.%d", hostver/10, hostver%10);
  1241.           break;
  1242.  
  1243.     } /* end switch (hostnum: external attributes format) */
  1244.  
  1245.     printf("%s %s %7lu %c%c %7lu %s %s %s\n", attribs, os[hostnum], 
  1246.       crec.uncompressed_size, (crec.general_purpose_bit_flag & 1)?
  1247.       ((crec.internal_file_attributes & 1)? 'T' : 'B') :   /* encrypted */
  1248.       ((crec.internal_file_attributes & 1)? 't' : 'b'),    /* plaintext */
  1249.       (crec.general_purpose_bit_flag & 8)? (crec.extra_field_length? 'X' : 'l')
  1250.                                          : (crec.extra_field_length? 'x' : '-'),
  1251.       crec.compressed_size, method[methnum],
  1252.       zipinfo_time(&crec.last_mod_file_date, &crec.last_mod_file_time),
  1253.       filename);
  1254.  
  1255. /*---------------------------------------------------------------------------
  1256.     Skip the extra field and/or the file comment, if any (the filename has
  1257.     already been printed, above).  That finishes up this file entry...
  1258.   ---------------------------------------------------------------------------*/
  1259.  
  1260.     SKIP_(crec.extra_field_length)
  1261.     SKIP_(crec.file_comment_length)
  1262.  
  1263.     return (error_in_archive);
  1264.  
  1265. } /* end function short_info() */
  1266.  
  1267.  
  1268.  
  1269.  
  1270.  
  1271. /*****************************/
  1272. /*  Function zipinfo_time()  */
  1273. /*****************************/
  1274.  
  1275. char *zipinfo_time(datez, timez)
  1276.     UWORD   *datez, *timez;
  1277. {
  1278.     UWORD         yr, mo, dy, hh, mm, ss;
  1279.     static char   d_t_str[21];
  1280.     static char   *month[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1281.                                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  1282.  
  1283.  
  1284.  
  1285. /*---------------------------------------------------------------------------
  1286.     Convert the file-modification date and time info to a string of the form 
  1287.     "23 Feb 1990 17:15:00" or "23-Feb-91 17:15," depending on value of lflag.
  1288.   ---------------------------------------------------------------------------*/
  1289.  
  1290.     yr = ((*datez >> 9) & 0x7f) + 80;     /* dissect date */
  1291.     mo = ((*datez >> 5) & 0x0f) - 1;
  1292.     dy = *datez & 0x1f;
  1293.  
  1294.     hh = (*timez >> 11) & 0x1f;           /* dissect time */
  1295.     mm = (*timez >> 5) & 0x3f;
  1296.     ss = (*timez & 0x1f) * 2;
  1297.  
  1298.     if (lflag == 2)
  1299.         sprintf(d_t_str, "%2u-%s-%u %02u:%02u", dy, month[mo], yr, hh, mm);
  1300.     else if (lflag > 9)  /* verbose listing format */
  1301.         sprintf(d_t_str, "%u %s %u %02u:%02u:%02u", dy, month[mo], yr+1900,
  1302.           hh, mm, ss);
  1303.  
  1304.     return(d_t_str);
  1305.  
  1306. } /* end function zipinfo_time() */
  1307.  
  1308.  
  1309.  
  1310.  
  1311.  
  1312. /********************************/
  1313. /*  Function open_input_file()  */
  1314. /********************************/
  1315.  
  1316. int open_input_file()
  1317. {                               /* return non-0 if open failed */
  1318.     /*
  1319.      *  open the zipfile for reading and in BINARY mode to prevent cr/lf
  1320.      *  translation, which would corrupt the bitstreams
  1321.      */
  1322.  
  1323. #ifndef UNIX
  1324.     zipfd = open(zipfn, O_RDONLY | O_BINARY);
  1325. #else
  1326.     zipfd = open(zipfn, O_RDONLY);
  1327. #endif
  1328.     if (zipfd < 1) {
  1329.         fprintf(stderr, "error:  can't open zipfile [ %s ]\n", zipfn);
  1330.         return (1);
  1331.     }
  1332.     return 0;
  1333. }
  1334.  
  1335.  
  1336.  
  1337.  
  1338.  
  1339. /************************/
  1340. /*  Function readbuf()  */
  1341. /************************/
  1342.  
  1343. int readbuf(buf, size)
  1344.     char *buf;
  1345.     register unsigned size;
  1346. {                               /* return number of bytes read into buf */
  1347.     register int count;
  1348.     int n;
  1349.  
  1350.     n = size;
  1351.     while (size) {
  1352.         if (incnt == 0) {
  1353.             if ((incnt = read(zipfd, inbuf, INBUFSIZ)) <= 0)
  1354.                 return (n-size);
  1355.             /* buffer ALWAYS starts on a block boundary:  */
  1356.             cur_zipfile_bufstart += INBUFSIZ;
  1357.             inptr = inbuf;
  1358.         }
  1359.         count = min(size, incnt);
  1360.         memcpy(buf, inptr, count);
  1361.         buf += count;
  1362.         inptr += count;
  1363.         incnt -= count;
  1364.         size -= count;
  1365.     }
  1366.     return (n);
  1367. }
  1368.